package linker

import (
	"bytes"
	"debug/elf"
	"rvld/src/utils"
)

// private

func findNull(data []byte, entSize int) int {
	if entSize == 1 {
		return bytes.Index(data, []byte{0})
	}

	for i := 0; i <= len(data)-entSize; i += entSize {
		bs := data[i : i+entSize]
		if utils.ThisAllZeros(bs) {
			return i
		}
	}

	return -1
}

func splitSection(ctx *Context, input_sec *InputSection) *MergeableSection {
	m := &MergeableSection{}
	shdr := input_sec.Shdr()

	m.Parent = GetMergedSectionInstance(ctx, input_sec.Name(), shdr.Type, shdr.Flags)

	m.P2Align = input_sec.P2Align

	data := input_sec.Contents

	offset := uint64(0)

	if shdr.Flags&uint64(elf.SHF_STRINGS) != 0 {
		for len(data) > 0 {
			end := findNull(data, int(shdr.EntSize))
			if end == -1 {
				utils.ThisFatal("[ERROR]: string is not null terminated")
			}

			sz := uint64(end) + shdr.EntSize
			substr := data[:sz]
			data = data[sz:]
			m.Strs = append(m.Strs, string(substr))
			m.FragOffsets = append(m.FragOffsets, uint32(offset))
			offset += sz
		}
	} else {
		if uint64(len(data))%shdr.EntSize != 0 {
			utils.ThisFatal("[ERROR]: section size is not multiple of entsize")
		}

		for len(data) > 0 {
			substr := data[:shdr.EntSize]
			data = data[shdr.EntSize:]
			m.Strs = append(m.Strs, string(substr))
			m.FragOffsets = append(m.FragOffsets, uint32(offset))
			offset += shdr.EntSize
		}
	}
	return m
}
